前篇簡單介紹了 RDBMS, NoSQL Database, Object Storage 的特性與適用場景
NoSQL Database 還可以再根據儲存方式細分, 今天會介紹以下幾種常見的
和名字一樣, 相較於 RDBMS 是列儲存 (row-based), Columnar 是行儲存 (column-based)
好處是可以只搜尋感興趣的欄位, 而不需要讀取無關的部分, 加速查詢時間
舉例來說
| name | age | gender |
|-------|-----|--------|
| Amy | 20 | f |
| Brian | 16 | m |
| Chloe | 18 | f |
| David | 22 | m |
如果我們想要撈出所有的女性
列儲存需要從左 (name) 到右 (gender) 掃過所有欄位, 即使我們的條件只有 gender 這一行, 所以比較沒有效率
行儲存則是直接定位到條件指定的欄位進行查詢, 所以比較有效率
常見的 Database 有 Cassandra, HBase, ClickHouse, Amazon Redshift, Vertica 等等
題外話: 其實 行儲存 有很多變種 (Column Family), 比如 Cassandra 其實是 Wide-Column Store, 和下面的 Document Database 有點像, 每列 可以有 不同的欄位, 但是沒有巢狀結構, 所以這邊視為 行儲存
其實 NoSQL 都有 key-value pair 的資料結構, 好處是擴展性強, 寫入速度快, 但讀取 "相對 RDBMS" 慢
這邊主要是指 "儲存的格式" , 比如 SSTable
常見的 Database 有 Memcached, Redis, Amazon DynamoDB, RocksDB, LevelDB
主要由 Document 和 Collection 構成
Document: 可以理解為 列儲存 的 列 (Record)
Collection: Documents 的集合
儲存的格式和 JSON 很像, 不過支援更多格式, 像 MongoDB 稱為 BSON (Binary JSON), 記得是 Key-Value Pair 就好
和 RDBMS 強調表間的關係不同, Document Database 不支援 RDBMS 的 JOIN, 且資料需要 Denormalize 加快存取速度
且由於是 Key-Value 儲存形式, 又沒有 ACID 的特型, 擴展性也比 RDBMS 好
舉個例子, RDBMS 可能會有下面設計 (符合 3NF)
user
| id | name | age | id_gender |
|----|-------|-----|-----------|
| 1 | Amy | 20 | 1 |
| 2 | Brian | 16 | 2 |
| 3 | Chloe | 18 | 1 |
| 4 | David | 22 | 2 |
gender
| id | gender |
|----|--------|
| 1 | f |
| 2 | m |
Document Database 則有兩種設計方法
[
{
"id": 1,
"name": "Amy",
"age": 20,
"gender": "f"
},
{
"id": 2,
"name": "Brian",
"age": 16,
"gender": "m"
},
{
"id": 3,
"name": "Chloe",
"age": 18,
"gender": "f"
},
{
"id": 4,
"name": "David",
"age": 22,
"gender": "m"
}
]
[
{
"id": 1,
"name": "Amy",
"age": 20,
"id_gender": 1
},
{
"id": 2,
"name": "Brian",
"age": 16,
"id_gender": 2
},
{
"id": 3,
"name": "Chloe",
"age": 18,
"id_gender": 1
},
{
"id": 4,
"name": "David",
"age": 22,
"id_gender": 2
}
]
genders collection
[
{
"id": 1,
"gender": "f"
},
{
"id": 2,
"gender": "m"
}
]
常見的有 CouchDB, MongoDB, Amazon DocumentDB, Elasticsearch (感謝留言補充)
Time-series Database 主要用於 Time-series 資料的存取
什麼是 Time-series 資料呢? 廣義來說, 只要帶有時間戳的資料都是 Time-series 資料
舉例來說, 我們將建立使用者的時間加上時間戳
| id | name | age | id_gender | timestamp |
|----|-------|-----|-----------|---------------------|
| 1 | Amy | 20 | 1 | 2023-08-05T12:00:00 |
| 2 | Brian | 16 | 2 | 2023-08-05T12:01:00 |
| 3 | Chloe | 18 | 1 | 2023-08-05T12:02:00 |
| 4 | David | 22 | 2 | 2023-08-05T12:03:00 |
但這其實沒什麼意義, 回歸到 Database 的本質, 是為了 "業務需求" 而存在的
如果只是單純加上時間戳, 只是多了冗余的資料而已
那麼換個角度想, 時間戳可以用來做什麼?
如果是遊戲服務, 或許可以記錄使用者的活動數據, 用來檢查異常行為 (外掛, 盜號等)
activity
| user_id | activity_type | times | timestamp |
|---------|---------------|-------|---------------------|
| 1 | login | 1 | 2023-08-05T12:00:00 |
| 1 | click | 5 | 2023-08-05T12:05:00 |
| 2 | login | 1 | 2023-08-05T12:01:00 |
| 2 | purchase | 1 | 2023-08-05T12:15:00 |
| 1 | logout | 1 | 2023-08-05T12:30:00 |
如果是雲端服務, 或許可以定時記錄伺服器資源的用量, 搭配 Alert System 即時通知
所以嚴格來說, Time-series 資料應該要符合以下兩點
等等, 這種 針對特定欄位查詢 的特性剛剛好像看過?
沒錯, Time-series Database 也可以用 行儲存!
但是相較於 行儲存, Time-series 資料通常有高頻的特性, 所以 Time-series Database 有針對 寫入 優化, 且因為會有大量的歷史資料, 所以也有壓縮 (Compression) 和 封存 (Archive) 的機制
由於 Time-series 資料多用於分析, 所以只要保住原始資料, 所有衍生的資料都可以透過 Write-Ahead Log (WAL) 重放 (Replay)
題外話: 客戶端採樣會有時區的問題, 所以多是伺服器端採樣
常見的有 InfluxDB, Prometheus
話說elasticsearch算不算NoSQL Database?
忘記寫了, 感謝提醒~
NoSQL 一個重要的特徵是 Schemaless (發現文章沒寫到囧)
所以根據此文章的分類方式, 來看看 elasticsearch 資料的儲存格式
elasticsearch 是用 Inverted Index 建立索引
透過將文件 tokenize 後, 紀錄每個字詞在文件出現的位置與次數來加速搜尋
舉例
假設我們有 3 份文件, 裡面各有一句話
1. A for apple.
2. B for banana.
3. C for cat.
elasticsearch 透過 inverted index 儲存格式會變成 (去除標點符號後)
a: [1]
for: [1, 2, 3]
apple: [1]
b: [2]
banana: [2]
c: [3]
cat: [3]
可以看出 elasticsearch 的儲存格式確實是 schemaless (index 不固定), 所以是 NoSQL Database 沒錯!